<?php

namespace wxml\models;

use common\libs\Util;
use wxml\models\user\User;
use Yii;
use wxml\libs\CommonModel;
use wxml\models\user\AR\UserAR;
use common\libs\RemoteHttp;
use wxml\models\order\AR\OrderAR;

/**
 * ContactForm is the model behind the contact form.
 */
class Weixin extends CommonModel
{
    private $appID;
    private $appSecret;
    private $mchId;
    private $siteAccessTokenCacheKey = 'weixin_lite_access_token';
    private $siteJsApiTicketCacheKey = 'weixin_lite_jsapi_ticket';
    private $siteUserLoginKey = 'weixin_lite__user_login_key';
    private $signKey = '&key=weixinlvacationcn1234567890abcde';
    private $recommendFriendAward = 0.5;
    private $signinCacheKey = 'signin_hongbao';

    public function __construct()
    {
        $this->appID = yii::$app->params['weixin']['appId'];
        $this->appSecret = yii::$app->params['weixin']['appSecret'];
        $this->mchId = yii::$app->params['weixin']['mchID'];
    }

    //刷新access_token
    public function refreshToken()
    {
    }

    //获取用户access_token
    public function login($code)
    {
        if (empty($code)) {
            Yii::info('未获取Code', 'access_token');
            $this->setError(-1, '未获取Code');

            return false;
        }
        $res = RemoteHttp::get('https://api.weixin.qq.com/sns/jscode2session',
        [
          'grant_type' => 'authorization_code',
          'js_code' => $code,
          'appid' => $this->appID,
          'secret' => $this->appSecret,
        ]);
        $accessToken = json_decode($res, true);
        if (isset($accessToken['errcode'])) {
            Yii::trace($res, 'access_token');
            $this->setError(-1, $accessToken['errmsg']);

            return false;
        } else {
            $user = UserAR::findOne(['weixin_openid' => $accessToken['openid']]);
            //用户不存在
            if (!$user) {
                //保存用户信息
                $user = new UserAR();
                $user->status = 1;
                $user->name = 'weixin_user';
                $user->create_time = time();
            }
            $user->weixin_openid = $accessToken['openid'];
            $user->weixin_session_key = $accessToken['session_key'];
            $user->save();
        }

        $open_id = $accessToken['openid'];
        $session_key = $accessToken['session_key'];
        $third_session = md5(md5(time()));
        $session_value = [
          'open_id' => $open_id,
          'session_key' => $session_key,
        ];
        Yii::$app->cache->set($third_session, serialize($session_value), 3600);

        return $third_session;
    }

    public static function checkIsLogin($key)
    {
        $cache = Yii::$app->cache;
        $accessToken = $cache->get($key);

        if (!$accessToken) {
        } else {
            $accessToken = unserialize($accessToken);
            $user = UserAR::findOne(['weixin_openid' => $accessToken['open_id']]);

            if ($user && $user->weixin_session_key == $accessToken['session_key']) {
                return $user;
            } else {
            }
        }

        return false;
    }

    //获取整站access_token 并缓存
    public function getSiteAccessToken()
    {
        $cache = Yii::$app->cache;
        $accessToken = $cache->get($this->siteAccessTokenCacheKey);
        if (!$accessToken) {
            $res = RemoteHttp::get('https://api.weixin.qq.com/cgi-bin/token', ['grant_type' => 'client_credential',
                                                                               'appid' => $this->appID,
                                                                               'secret' => $this->appSecret, ]);
            $json = json_decode($res, true);
            if (isset($json['errcode'])) {
                Yii::error($res, $this->siteAccessTokenCacheKey);
                $this->setError(-1, $json['errmsg']);

                return false;
            } else {
                $accessToken = $json['access_token'];
                $cache->set($this->siteAccessTokenCacheKey, serialize($accessToken), $json['expires_in']);
            }
        } else {
            $accessToken = unserialize($accessToken);
        }

        return $accessToken;
    }

    //获取jsapi签名
    public function getJsApiSignature($url = null)
    {
        if (empty($url)) {
            $url = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : "{$_SERVER['REQUEST_SCHEME']}://{$_SERVER['HTTP_HOST']}{$_SERVER['REQUEST_URI']}";
        }
        $timeStamp = time();
        $nonceStr = Util::getRandCode(16);
        $jsapiTicket = $this->getJsApiTicket();

        if ($jsapiTicket === false) {
            return false;
        }
        $signatureParams = ['noncestr' => $nonceStr, 'jsapi_ticket' => $jsapiTicket, 'timestamp' => $timeStamp,
                            'url' => $url, ];

        $signature = $this->getSign($signatureParams, 'sha1', false);

        return ['appId' => $this->appID, 'timestamp' => $timeStamp, 'nonceStr' => $nonceStr,
                'signature' => $signature, ];
    }

    //获取jsapi_ticket
    public function getJsApiTicket()
    {
        $cache = Yii::$app->cache;
        $jsApiTicket = $cache->get($this->siteJsApiTicketCacheKey);
        if (!$jsApiTicket) {
            $access_token = $this->getSiteAccessToken();
            $res = RemoteHttp::get("https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi&access_token={$access_token}");
            $json = json_decode($res, true);
            if (isset($json['errcode']) && !empty($json['errcode'])) {
                Yii::error($res, $this->siteJsApiTicketCacheKey);
                $this->setError(-1, $json['errmsg']);

                return false;
            } else {
                $jsApiTicket = $json['ticket'];
                $cache->set($this->siteJsApiTicketCacheKey, serialize($jsApiTicket), $json['expires_in']);
            }
        } else {
            $jsApiTicket = unserialize($jsApiTicket);
        }

        return $jsApiTicket;
    }

    //获取微信支付签名
    public function getWxJsPaySignature($prepay_id)
    {
        $timeStamp = (string) time();
        $nonceStr = Util::getRandCode(16);
        $signType = 'MD5';
        $package = "prepay_id=$prepay_id";

        $signatureParams = ['appId' => $this->appID, 'timeStamp' => $timeStamp, 'nonceStr' => $nonceStr,
                            'package' => $package, 'signType' => $signType, ];

        $paySign = $this->getSign($signatureParams, 'md5', true, $this->signKey);

        return ['appId' => $this->appID, 'timeStamp' => $timeStamp, 'nonceStr' => $nonceStr, 'package' => $package,
                'signType' => $signType, 'paySign' => $paySign, ];
    }

    //发起统一下单
    public function unifiedorder($product_title, $order_no, $total_fee, $open_id, $prepay_id = null)
    {
        if (!$prepay_id) {
            $postParams = ['appid' => $this->appID, 'mch_id' => $this->mchId, 'nonce_str' => Util::getRandCode(16),
                           'sign_type' => 'MD5', 'body' => mb_strcut("购书-{$product_title}", 0, 30, 'UTF-8'),
                           'out_trade_no' => $order_no, //{$product_info['title']}
                           'total_fee' => $total_fee, 'spbill_create_ip' => Util::getIp(),
                           'notify_url' => 'https://weixinapp.lvacation.cn/order/pay_notify', 'trade_type' => 'JSAPI',
                           'openid' => $open_id, ];

            $sign = $this->getSign($postParams, 'md5', true, $this->signKey);
            $postParams['sign'] = $sign;
            $xml = Util::arrayToXml($postParams);
            $res = RemoteHttp::postXmlString('https://api.mch.weixin.qq.com/pay/unifiedorder', $xml);
            Yii::error(print_r($postParams, true));
            Yii::error($res);
            $result = simplexml_load_string($res, 'SimpleXMLElement', LIBXML_NOCDATA);

            if (isset($result->return_code) && $result->return_code == 'SUCCESS' && $result->result_code == 'SUCCESS') {
                $order_info = OrderAR::findOne(['order_no' => $order_no]);
                $order_info->third_pay_no = $result->prepay_id;
                $order_info->pay_type = 'WEIXIN_LITE';
                $order_info->update_time=time();
                $order_info->save();

                return $this->getWxJsPaySignature($result->prepay_id);
            } else {
                $this->setError(-1, $result->err_code_des ? $result->err_code_des : $result->return_msg);

                return false;
            }
        } else {
            return $this->getWxJsPaySignature($prepay_id);
        }
    }

    //签名
    public function getSign($signatureParams, $type = 'md5', $upper_case = true, $signString = '')
    {
        ksort($signatureParams);
        $stringSignTemp = '';
        foreach ($signatureParams as $key => $val) {
            $stringSignTemp .= $key.'='.$val.'&';
        }
        $stringSignTemp = substr($stringSignTemp, 0, -1).$signString;
        $stringSignTemp = $type == 'md5' ? md5($stringSignTemp) : sha1($stringSignTemp);
        if ($upper_case) {
            $stringSignTemp = strtoupper($stringSignTemp);
        }

        return $stringSignTemp;
    }

    //发送模板消息
    public function sendTemplateMessage($temp_code, $open_id, $params)
    {
        $access_token = $this->getSiteAccessToken();
        $template = yii::$app->params['WeixinTemplateMessage'][$temp_code];
        $postData = $this->getTemplateParams($params, $template);
        $postData['touser'] = $open_id;
        $res = RemoteHttp::postJson("https://api.weixin.qq.com/cgi-bin/message/wxopen/template/send?access_token={$access_token}", $postData);
        $json = json_decode($res, true);
        if (isset($json['errcode']) && !empty($json['errcode'])) {
            $this->setError(-1, $json['errmsg']);

            return false;
        } else {
            return true;
        }
    }

    public function dealWithEvent($params)
    {
        $contentStr = '';
        if (isset($params['Event'])) {
            switch ($params['Event']) {
                case 'subscribe':
                    $contentStr = '恭喜你迈出【悠长假期】的第一步！'."\n".'多种旅行玩法等你来发现'."\n";
                case 'SCAN':
                    $contentStr = $this->dealWithScan($params);
                default:
                    $contentStr .= "\n".'微信9:00~18:00也开通在线客服服务，可以直接在公众号中与小悠交流';
                    $contentStr = $this->responseText($params, $contentStr);
                    break;
            }
        }
        if (isset($params['MsgType']) && $params['MsgType'] == 'text') {
            $contentStr = $this->dealWithText($params);
        }

        return $contentStr;
    }

    public function dealWithText($params)
    {
        $text = '';

        switch ($params['Content']) {
            case '签到':
                if (date('H') < 9) {
                    $text = $this->responseText($params, '领红包活动每天9点开始 别心急哦！');
                } else {
                    $text = $this->responseText($params, '今天的问题：'."\n".'上海迪士尼在上海浦东哪个镇？'."\n".'周浦镇'."\n".'川沙新镇'."\n".'南汇新城镇'."\n".'唐镇');
                }
                break;
            case '川沙新镇':
                if (date('H') < 9) {
                    $text = $this->responseText($params, '领红包活动每天9点开始 别心急哦！');
                } else {
                    $cache = Yii::$app->cache;
                    $signinResult = $cache->get($this->signinCacheKey.date('Y-m-d'));
                    if (!$signinResult) {
                        $signinResult = array();
                    } else {
                        $signinResult = unserialize($signinResult);
                    }
                    if (count($signinResult) > 2) {
                        //一天领用的红包不超过3个
                        $text = $this->responseText($params, '你来晚了，红包领完啦，明天请早');
                    } else {
                        if (in_array($params['FromUserName'], $signinResult)) {
                            $text = $this->responseText($params, '今天已经领过了 明天继续加油！');
                        } else {
                            $hongbaoResult = $this->sendRedpack($params['FromUserName'], '签到奖励', 1);
                            if ($hongbaoResult) {
                                $text = $this->responseText($params, "恭喜答对了\n我们将奖励一个红包给你 快拆开看一下吧");
                                $signinResult[] = $params['FromUserName'];
                                $cache->set($this->signinCacheKey.date('Y-m-d'), serialize($signinResult), 3600 * 24);
                            } else {
                                $text = $this->responseText($params, '可惜你来晚了，红包领完啦，明天请早！');
                            }
                        }
                    }
                }
                break;
            default:
                $text = false;
                break;
        }

        return $text;
    }

    public function dealWithScan($params)
    {
        $open_id = $params['FromUserName'];
        $user = UserAR::findOne(['weixin_openid' => $open_id]);
        $responseTextToUser = '欢迎回到【悠长假期】!'."\n".'多种旅行玩法等你来发现'."\n";

        if ($user) {
            //老用户无任何操作
        } else {
            //新用户给推荐人送
            $qrcode = QrcodeAR::findOne(['ticket' => $params['Ticket']]);
            yii::error('获取微信用户信息:'.print_r($qrcode, true));
            if ($qrcode) {
                $dbTrans = Yii::$app->db->beginTransaction();
                try {
                    //旅行达人推广码
                    if ($qrcode->type == 1) {
                        $from_user_id = $qrcode->user_id;

                        $fromUser = UserAR::findOne(['id' => $from_user_id]);
                        $userInfo = (new self())->getUserInfo($params['FromUserName']);
                        //注册一个新用户
                        yii::error('获取微信用户信息:'.print_r($userInfo, true));
                        ////保存用户信息
                        $newUser = new UserAR();
                        $newUser->name = $userInfo['nickname'];
                        $newUser->nickname = $userInfo['nickname'];
                        $newUser->sex = $userInfo['sex'];
                        $newUser->avatar = $userInfo['headimgurl'];
                        $newUser->weixin_openid = $params['FromUserName'];
                        $newUser->status = 1;
                        $newUser->leader_id = $from_user_id;
                        $saveNewUserResult = $newUser->save();
                        if (!$saveNewUserResult) {
                            throw new \Exception('保存新用户信息失败');
                        }

                        //添加资金记录
                        $balanceRecordAR = new BalanceRecordAR();
                        $balanceRecordAR->user_id = $from_user_id;
                        $balanceRecordAR->amount = $this->recommendFriendAward;
                        $balanceRecordAR->balance = $fromUser->balance + $this->recommendFriendAward;
                        $balanceRecordAR->original = $fromUser->balance;
                        $balanceRecordAR->from_user_id = 0;
                        $balanceRecordAR->type = 1;
                        $balanceRecordAR->remark = '旅行达人奖励(新用户扫码关注)';
                        $balanceRecordSaveResult = $balanceRecordAR->save();
                        if (!$balanceRecordSaveResult) {
                            throw new \Exception('保存旅行达人奖励记录失败');
                        }
                        //给旅行达人加余额
                        $fromUser->balance = $fromUser->balance + $this->recommendFriendAward;
                        $saveFromUserResult = $fromUser->save();
                        if (!$saveFromUserResult) {
                            throw new \Exception('保存旅行达人奖励失败');
                        }
                        $dbTrans->commit();

                        $this->sendTemplateMessage('NewerScanQrcode', $fromUser['weixin_openid'], array('keyword1' => $fromUser['nickname'],
                                                                                                        'keyword2' => $newUser['nickname'],
                                                                                                        'remark' => '你已获得'.$this->recommendFriendAward.'元推荐奖励。快去分享旅游产品，获取更多奖金！', ));
                        $responseTextToUser = '恭喜你迈出【悠长假期】的第一步！'."\n".'多种旅行玩法等你来发现'."\n";
                    }
                } catch (\Exception $e) {
                    $dbTrans->rollback();
                    $this->errMsg = $e->getMessage();
                    yii::error($e->getMessage());
                }
            } else {
                //未找到推广码
            }
        }

        return $responseTextToUser;
    }

    /**
     * 红包发放.
     */
    public function sendRedpack($open_id = 'ojwZ9v9UVTinUDXUmv4g-93GG2Hg', $act_name = '会员返利', $total = '1')
    {
        $postParams = ['nonce_str' => Util::getRandCode(16), 'mch_billno' => 'LVHB' + time(), 'mch_id' => $this->mchId,
                       'wxappid' => $this->appID, 'send_name' => '悠长假期旅行网', 're_openid' => $open_id,
                       'total_amount' => '100', 'total_num' => $total, 'wishing' => '世界那么大，好好放个假',
                       'client_ip' => Util::getIp(), 'act_name' => $act_name, 'remark' => '猜越多得越多，快来抢！', ];
        $sign = $this->getSign($postParams, 'md5', true, $this->signKey);
        $postParams['sign'] = $sign;
        $xml = Util::arrayToXml($postParams);
        $res = RemoteHttp::postSSL('https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack', $xml, 60, ['Content-Type: application/xml',
                                                                                                             'Content-Length: '.strlen($xml), ]);
        Yii::error(print_r($postParams, true));
        Yii::error($res);
        $result = simplexml_load_string($res, 'SimpleXMLElement', LIBXML_NOCDATA);
        if (isset($result->return_code) && $result->return_code == 'SUCCESS' && $result->result_code == 'SUCCESS') {
            return true;
        } else {
            $this->setError(-1, $result->err_code_des ? $result->err_code_des : $result->return_msg);

            return false;
        }
    }

    /**
     * 付款.
     */
    public function transfers($open_id = 'ojwZ9v9UVTinUDXUmv4g-93GG2Hg',  $total = '1')
    {
        $postParams = ['nonce_str' => Util::getRandCode(16), 'partner_trade_no' => 'LVPAY' + time(), 'mchid' => $this->mchId,
                       'mch_appid' => $this->appID, 'check_name' => 'NO_CHECK', 'openid' => $open_id,
                       'amount' => $total, 'desc' => '采购',
                       'spbill_create_ip' => Util::getIp(), ];
        $sign = $this->getSign($postParams, 'md5', true, $this->signKey);
        $postParams['sign'] = $sign;
        $xml = Util::arrayToXml($postParams);
        $res = RemoteHttp::postSSL('https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers', $xml, 60, ['Content-Type: application/xml',
                                                                                                             'Content-Length: '.strlen($xml), ]);
        Yii::error(print_r($postParams, true));
        Yii::error($res);
        $result = simplexml_load_string($res, 'SimpleXMLElement', LIBXML_NOCDATA);
        if (isset($result->return_code) && $result->return_code == 'SUCCESS' && $result->result_code == 'SUCCESS') {
            return true;
        } else {
            $this->setError(-1, $result->err_code_des ? $result->err_code_des : $result->return_msg);

            return false;
        }
    }

    /**
     * @deprecated 获取微信用户信息
     *
     * @param $open_id
     *
     * @return mixed
     */
    public function getUserInfo($open_id)
    {
        $access_token = $this->getSiteAccessToken();
        //使用access_token获取用户信息
        $userResult = RemoteHttp::get('https://api.weixin.qq.com/cgi-bin/user/info', ['access_token' => $access_token,
                                                                                      'openid' => $open_id,
                                                                                      'lang' => 'zh_CN', ]);
        $userResult = preg_replace("#(\\\ue[0-9a-f]{3})#ie", "addslashes('\\1')", $userResult);

        $userInfo = json_decode($userResult, true);
        if (!empty($userInfo['errcode'])) {
            $this->setError(-1, $userInfo['errmsg']);

            return false;
        }

        return $userInfo;
    }

    /**
     * @deprecated 申请二维码ticket
     *
     * @param string $action_name
     * @param int    $scene_id
     * @param string $scene_str
     *
     * @return mixed $ticket
     */
    public function getQrcodeTicket($action_name = 'QR_SCENE', $scene_id = 1, $scene_str = '')
    {
        $access_token = $this->getSiteAccessToken();

        //使用access_token获取用户信息
        $qrcodeResult = RemoteHttp::post("https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=$access_token", json_encode(['expire_seconds' => 2592000,
                                                                                                                                    'action_name' => $action_name,
                                                                                                                                    'scene_info' => ['scene' => ['scene_id' => $scene_id,
                                                                                                                                                                 'scene_str' => $scene_str, ]], ]));
        $qrcode = json_decode($qrcodeResult, true);

        return $qrcode;
    }

    private function getTemplateParams($params, $temp_params)
    {
        foreach ($params as $key => $obj) {
            $temp_params['data'][$key]['value'] = $obj;
        }

        return $temp_params;
    }

    private function responseText($object, $content, $flag = 0)
    {
        $textTpl = '<xml>
                    <ToUserName><![CDATA[%s]]></ToUserName>
                    <FromUserName><![CDATA[%s]]></FromUserName>
                    <CreateTime>%s</CreateTime>
                    <MsgType><![CDATA[text]]></MsgType>
                    <Content><![CDATA[%s]]></Content>
                    <FuncFlag>%d</FuncFlag>
                    </xml>';
        $resultStr = sprintf($textTpl, $object['FromUserName'], $object['ToUserName'], time(), $content, $flag);

        return $resultStr;
    }
}
